package com.lcf.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.lcf.framework.utils.UserUtils;
import com.lcf.framework.vo.PageVO;
import com.lcf.system.dao.MovieCollectDao;
import com.lcf.system.entity.Movie;
import com.lcf.system.entity.MovieCollect;
import com.lcf.system.entity.MovieType;
import com.lcf.system.query.MovieCollectPageQuery;
import com.lcf.system.service.MovieCollectService;
import com.lcf.system.vo.MovieCollectVO;
import com.lcf.system.vo.MovieTypeVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 收藏(MovieCollect)表服务实现类
 *
 * @author lcf
 * @since 2025-05-07 22:23:22
 */
@Service("movieCollectService")
public class MovieCollectServiceImpl extends ServiceImpl<MovieCollectDao, MovieCollect> implements MovieCollectService {

    @Override
    public PageVO<MovieCollectVO> page(MovieCollectPageQuery query) {
        Page<MovieCollect> page = Db.lambdaQuery(MovieCollect.class)
                .eq(query.getUserId() != null, MovieCollect::getUserId, query.getUserId())
                .eq(query.getMovieId() != null, MovieCollect::getMovieId, query.getMovieId())
                .eq(MovieCollect::getIsCollect, 1)
                .orderByDesc(MovieCollect::getCreateTime)
                .page(query.toPage());

        if (page != null && page.getRecords() != null && !page.getRecords().isEmpty()) {
            PageVO<MovieCollectVO> result = new PageVO<>(page, MovieCollectVO.class);

            List<Long> movieIdList = result.getList().stream().map(MovieCollectVO::getMovieId).distinct().toList();
            List<MovieType> movieTypes = Db.lambdaQuery(MovieType.class).in(MovieType::getMovieId, movieIdList).list();
            Map<Long, List<MovieTypeVO>> map = movieTypes.stream().map(x -> BeanUtil.copyProperties(x, MovieTypeVO.class))
                    .collect(Collectors.groupingBy(MovieTypeVO::getMovieId));

            result.getList().forEach(x -> x.setMovieTypes(map.get(x.getMovieId())));

            return result;
        }

        return new PageVO<>(page, MovieCollectVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void collect(long movieId) {
        MovieCollect exist = Db.lambdaQuery(MovieCollect.class)
                .eq(MovieCollect::getUserId, UserUtils.getUserId())
                .eq(MovieCollect::getMovieId, movieId)
                .one();

        if (exist != null) {
            Db.lambdaUpdate(MovieCollect.class).eq(MovieCollect::getId, exist.getId()).set(MovieCollect::getIsCollect, 1).update();
            if (exist.getIsCollect() == 0) {
                Db.lambdaQuery(Movie.class).eq(Movie::getId, movieId).oneOpt().ifPresent(x -> {
                    x.setCollectTimes(x.getCollectTimes() + 1);
                    x.updateById();
                });
            }
        } else {
            MovieCollect movieCollect = new MovieCollect();
            movieCollect.setIsCollect(1);
            movieCollect.setMovieId(movieId);
            movieCollect.setUserId(UserUtils.getUserId());
            movieCollect.insert();

            Db.lambdaQuery(Movie.class).eq(Movie::getId, movieId).oneOpt().ifPresent(x -> {
                x.setCollectTimes(x.getCollectTimes() + 1);
                x.updateById();
            });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelCollect(long movieId) {
        Db.lambdaUpdate(MovieCollect.class)
                .eq(MovieCollect::getUserId, UserUtils.getUserId())
                .eq(MovieCollect::getMovieId, movieId)
                .set(MovieCollect::getIsCollect, 0)
                .update();

        Db.lambdaQuery(Movie.class).eq(Movie::getId, movieId).oneOpt().ifPresent(x -> {
            x.setCollectTimes(Math.max(x.getCollectTimes() - 1, 0));
            x.updateById();
        });
    }
}

